/**
 * 23.内存初始化函数 memset() & memcpy() & others...
 */
#include <stdio.h>
#include <stdlib.h>

void memset_test();
void memcpy_test();
void memmove_test();
void memcmp_test();

int main() {
    //1.内存初始化函数 memset()
    memset_test();
    //2.
    memcpy_test();
    //3.
    memmove_test();
    //4.
    memcmp_test();

    return EXIT_SUCCESS;
}

/**
 * 7.内存初始化函数 memset(), (string.h / memory.h)
 *   https://www.bilibili.com/video/BV1vs411n7TH?p=99
 *
 *   将 Dst 的内存区域的前 "Size 个字节"以参数 Val 填入
 *   @param _Dst: 需要操作内存的首地址.
 *   @param _Val: 填充的字符, unsigned char 类型, 范围0~255
 *   @param _Size: 指定需要设置多少个字节(单位是Byte)
 *   @return _Dst 的首地址
 *   void * __cdecl memset(void *_Dst,int _Val,size_t _Size);
 */
#include <string.h>
void memset_test() {
    int size = sizeof(int) * 10;
    int *p = (int*) malloc(size);       //stdlib.h
    for (int i = 0; i < 10; ++i) {
        printf("p[%d] = %d\n", i, p[i]);//不定值
    }

    //string.h / memory.h, 注意 size 大小=40
    memset(p, 0, size);
    printf("memset(p, 0, size), p[10] = ");
    for (int i = 0; i < 10; ++i) {
        printf("%d ", p[i]);            //全是0
    }
    puts("");

    /**
     * int 4个字节 = 32位, 每一个字节存储的是 00000001
     * ∴ 4个字节存储的是: 00000001 00000001 00000001 00000001
     *    对应的10进制: 16843009
     */
    memset(p, 1, size);
    for (int i = 0; i < 10; ++i) {
        printf("p[%d] = %d\n", i, p[i]);//全是 16843009
    }
    free(p);                            //释放内存

    /**
     * 给数组重置
     */
    char ch[10];
    memset(ch, 'A', 10 - 1);
    ch[9] = 0;      //最后一个 '\0', 否则打印出来乱码
    printf("ch[10] = %s\n", ch);        //AAAAAAAAA
}

/**
 * 拷贝 _Src 所指的内存容量的前 Size 字节到 Dst 所指的内存地址上.
 * 注意: Dst & Src 所指的内存空间"不可重叠", 可能会导致程序报错.
 * @param _Dst: 目的内存首地址
 * @param _Src: 源内存首地址
 * @param _Size: 指定需要copy的大小(单位是Byte)
 * @return Dst 首地址
 * void * __cdecl memcpy(void * __restrict__ _Dst,const void * __restrict__ _Src,size_t _Size) __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
 */
void memcpy_test() {
    int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int size = sizeof(int) * 10;
    int *p = malloc(size);
    memcpy(p, arr, size);
    printf("memcpy(), p[10] = ");
    for (int i = 0; i < 10; ++i) {
        printf("%d ", p[i]);        //0~9
    }
    puts("");
    free(p);


    /**
     * strcpy() 遇到\0 停止,
     * memcpy() 遇到\0 不会停止.
     */
    char ch[] = "hello\0 world!";
    char str[100];
    strcpy(str, ch);
    printf("strcpy(): str = %s\n", str);//hello

    memcpy(str, ch, 13);
    printf("memcpy(): str = ");
    for (int i = 0; i < 12; ++i) {
        printf("%c", str[i]);           //hello  world
    }
    puts("");


    /**
     * 将5,6,7 拷贝到 3,4,5
     * 内存空间"不可重叠", 可能会导致程序报错.
     */
    memcpy(&arr[3], &arr[5], 4*3);
    printf("memcpy(), 将5,6,7 拷贝到 3,4,5, arr[10] = ");
    for (int i = 0; i < 10; ++i) {
        printf("%d ", arr[i]);      //0 1 2 5 6 7 6 7 8 9
    }
    puts("");
}

/**
 * memmove()功能用法和 memcpy()一样, 区别在于: dest 和 src所指的内存空间重叠时,
 * memmove()仍能处理, 但执行效率比 memcpy() 低一些.
 * void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size) __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
 */
void memmove_test() {
    int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int size = sizeof(int) * 10;
    int *p = malloc(size);
    memmove(&arr[3], &arr[5], 4*3);
    printf("memmove(), 将5,6,7 拷贝到 3,4,5, arr[10] = ");
    for (int i = 0; i < 10; ++i) {
        printf("%d ", arr[i]);      //0 1 2 5 6 7 6 7 8 9
    }
    puts("");
    free(p);
}

/**
 * 比较 _Buf1 & _Buf2 所指向内存区域的前 _Size 个字节
 * @param _Buf1: 内存首地址1
 * @param _Buf2: 内存首地址2
 * @param _Size: 需要比较前 _Size 个字节
 * @return =0: 相等
 *         >0: 大于
 *         <0: 小于
 * int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size);
 */
void memcmp_test() {
    int arr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int arr2[] = {0, 1, 2, 3, 4, 5};
    int value1 = memcmp(arr1, arr2, 4 * 5);
    printf("memcmp(arr1, arr2, 4 * 5), 比较结果: %d\n", value1);//0: 相同
    int value2 = memcmp(arr1, arr2, 4 * 6 + 1);
    printf("memcmp(arr1, arr2, 4 * 6 + 1), 比较结果: %d\n", value2);//1: 大于
}